// 封装一个网络请求的方式（造车）
import axios2 from 'axios'
import router from '@/router'
import store from '@/store'
import { refreshTokenAPI } from '@/api'
// import bigInt from 'json-bigint' // 专门处理大数的
const bigInt = require('json-bigint')({ storeAsString: true })// 以这种方式引入，是为了把大数以字符串的形式进行返回
// 需求：不感兴趣的文章id超过了16位有效数
// 原因：axios再把数据（Json,19位字符串）请求回来后，帮吧json字符串====>js的格式
// 此时已经把精度破坏了
// 解决：自己重构，编写转json字符串的过程
const axios = axios2.create({
  // axios2创建一些配置项，把响应数据过程自己写，返回一个全新的axios方法
  transformResponse: [function (data) { // 对内容进行处理
    // data:就是本次请求获取的数据 是json字符串
    // 在这里可以对它进行进一步的处理 -- JSONbig
    // 后端返回数据可能不是 JSON 字符串，而JSONbig.parse()只能处理JSON字符串
    // 所以，为了保证代码可以正常执行，这里引入try-catch来捕获异常
    if (data.length === 0) {
      return ''
    } else {
      try {
        // 尝试着进行大数的处理
        // 将json字符串转换成JS数据类型（相比json.parse,会对大数进行处理）把数据转换为BigInt类型对象，而不是普通的number
        return bigInt.parse(data)
      } catch {
        // 大数处理失败时的后备方案
        return JSON.parse(data)
      }
    }
  }]
})

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  // 如果vuex有token（保存的token或者是默认返回的''）
  // ''的结果是undefinded,就加上Authorization，
  // 否则就是刷新token的情况
  if (store.state.token.length > 0 && config.headers.Authorization === undefined) {
    config.headers.Authorization = `Bearer ${store.state.token}`
  }
  return config
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 添加响应拦截器
axios.interceptors.response.use(function (response) { // 2xx 3xx
  // 对响应数据做点什么
  return response
}, async function (error) { // 报错4xx/5xx进入这里
  // 对响应错误做点什么
  if (error.response.status === 401) {
  // token认证失败，
  // token无用了，所以把token清除，确保路由守卫的if进不去
  // token续签解决方式1：强制到登录页，从新获取token
    // store.commit('setToken', '')
    // router.push({ path: '/login' })
    // token续签方式2：更新token
    const [, res] = await refreshTokenAPI()
    console.log(res)
    // 新的token替换就得token()
    store.commit('setToken', res.data.data.token)
    // 更新token,需要从新发一次请求（上次请求因为token过期了，没有成功）
    error.config.headers.Authorization = res.data.data.token
    return axios(error.config)
  } else if (error.response.status === 403) {
    // 如果refresh过期了就强跳转到登录页
    store.commit('refreshToken', '')
    store.commit('setToken', '')
    router.push({ path: '/login' })
  }
  return Promise.reject(error)
})
axios.defaults.baseURL = 'http://toutiao-app.itheima.net'
// axios.defaults.baseURL = 'http://localhost:8000'
export default ({
  // 解构赋值
  // { url: url,methods: methods,data: data,
  //   params: params,headers: headers} =
  // {
  //   url: '请求地址'， methods： '请求方式'，}
  url,
  method = 'GET',
  data,
  params,
  headers
}) => {
  // 结论：一个promise有两个参数，resolve代表成功，reject代表失败
  //  resolve ->then,reject ->catch()
  // 结论：then()或catch（）都会在原地返回一个全新的promise对象
  // 结论：then函数体内的return，会把值返回给下一个then函数
  // 结论：catch函数体内的return，会把值返回给下一个then函数

  // axios原地返回一个promise对象
  // 把promise对象return到api上的方法上
  const PA = axios({
    url,
    method,
    data,
    params,
    headers

  })
  const PB = PA.then((res) => {
    // [错误对象，成功对象]
  // 如果第一位有值，就证明失败了
    return [null, res]
  }).catch((err) => {
    return [err, null]
  })
  return PB
  // 改天换了一种请求方式，直接改内部
  // return $.ajax({
  //   url,
  //   type:methods,
  //   data,
  // })
  // 使用request导出网络请求的方式， 配置对象的参数不确定，那就自定义函数，靠外面传入的具体的值
}
